rest-framework 中文文档




rest-framework框架的介绍


  • rest-framework 是根据 RESTful 规范开发出来的一套 Django 的 API 框架

  • rest-framework 是建立在CBV基础上使用的 -> 通俗理解: 如果要是用 rest-framework,那么就一定要使用 CBV 去编写视图

  • rest-framework 的作用: 开发符合 RESTful 规范的接口

  • rest-framework 的10个功能(按请求顺序排序): 路由 视图 版本 认证 权限 频率 解析器 序列化 分页 渲染器

csrf token 的问题


  • 在使用 rest-framework 编写接口的时候会默认忽略掉 csrf token 认证中间件

    • 原理: 在 .as_view() 返回 view 视图函数的时候会在 view 视图函数上加上 csrf_exempt 装饰器,使其忽略 csrf token 的认证


  • 如果在编写接口的时候还是发生了 csrf token 问题的解决办法

    • 问题一: Postman 可以正常发送请求,但是在浏览器上无法正常发送

      • 解决办法一: 以 vue 项目为例: 查看 cookie 中是否存在 csrf token 的相关 cookie,如果存在清楚浏览器所有 cookie 即可

      • 解决办法二: 以 vue 项目为例: 先注释掉 csrf token 中间件,然后查看浏览器是否可以正常发送请求,如果可以,删除掉 csrf token 中间件的注释,给视图类下的视图函数单独添加  csrf_exempt 装饰器

from rest_framework.views import APIView
from rest_framework.response import Response
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt

class Test(APIView):
  @method_decorator(csrf_exempt)  # 给类里面的方法加装饰器  需要导入一个方法method_decorator
  def post(self, request):
    return Response({'a': 1})

    • 问题一: Postman 可以无法发送请求,浏览器上也无法正常发送

      • 解决办法: 先注释掉 csrf token 中间件,然后查看Postman是否可以正常发送请求,如果可以,删除掉 csrf token 中间件的注释,给视图类下的视图函数单独添加  csrf_exempt 装饰器

本笔记本所使用的数据库


# models.py

from django.db import models


class User(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)
    type_choices = ((1, '普通用户'), (2, 'VIP'), (3, 'SVIP'))
    user_type = models.IntegerField(choices=type_choices, default=1)

    def __str__(self):
        return self.username

    class Meta:
        verbose_name = "用户表"
        verbose_name_plural = verbose_name


class Token(models.Model):
    user = models.OneToOneField(to='User')
    token = models.CharField(max_length=128)

    def __str__(self):
        return self.token

    class Meta:
        verbose_name = "Token表"
        verbose_name_plural = verbose_name


class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name='书名')
    price = models.IntegerField(verbose_name='价格')
    pub_date = models.DateField(verbose_name='出版日期')
production_date = models.DateTimeField(verbose_name='生产日期', null=True)
    publish = models.ForeignKey("Publish", verbose_name='出版社')
    authors = models.ManyToManyField("Author", verbose_name='作者')

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "书籍表"
        verbose_name_plural = verbose_name


class Publish(models.Model):
    name = models.CharField(max_length=32, verbose_name='出版社名称')
    email = models.EmailField(verbose_name='邮箱')

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = "出版社表"
        verbose_name_plural = verbose_name


class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name='姓名')
    age = models.IntegerField(verbose_name='年龄')

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = "作者表"
        verbose_name_plural = verbose_name

rest-framework 的下载与配置


1. 下载 rest-framework 

pip3 install djangorestframework -i https://pypi.douban.com/simple # 使用豆瓣的镜像

2. 注册 rest-framework

# settings.py

INSTALLED_APPS = [
……
    'rest_framework',
]

接口类的编写规范


  • 在编写接口的时候要注意不能出现异常导致程序运行中断,而是使用 try 对异常进行捕获防治程序运行中断

  • 编写好每个异常的状态码(即: code),每个状态码就代表着一个错误信息

  • 注意: 在本章节中只有这里使用了接口类编写规范,其他栏目没有使用需要注意,且一定要按照该规范编写

# response.py

# 返回给前端的数据结构
class BaseResponse(object):
    def __init__(self):
        self.code = 0
        self.data = None
        self.msg = ''

    @property
    def dic(self):
        return self.__dict__

# exceptions.py

# 自定义异常类
class CommonException(Exception):
    def __init__(self, code, msg):
        self.code = code
        self.msg = msg

# views.py

from rest_framework.views import APIView
from rest_framework.response import Response

from django.core.exceptions import ObjectDoesNotExist  # 如果查询不到数据会抛出该错误

from api.utils.response import BaseResponse
from api.utils.exceptions import CommonException  # 自定义异常类


class Spec(APIView):
    def get(self):
        res = BaseResponse()
        try:
            obj1 = 表类.objects.get(pk=xxx)  # .get() 方法如果查询不到就会抛出 ObjectDoesNotExist 异常
            obj2 = 表类.objects.filter(pk=xxx).first()  # 如果查询不到不会抛出异常,只会返回 None

            if not obj2:
                raise CommonException(1002, 'xxx不存在2')

            res.data = {
                'xxx': obj1.xxx,
                'xxx': obj2.xxx
            }

        except ObjectDoesNotExist as e:
            res.msg = 'xxx不存在1'
            res.code = 1001
        except CommonException as e:
            res.msg = e.msg
            res.code = e.code
        except Exception as e:
            print(e)
# 捕获其他不知道的异常,然后写入日志中
        return Response(res.dic)

APIView 的 request 对象 


1. APIView 的 request对象 说明

  • 这里所指的request对象就是 FBV 或 CBV 中的 request 对象

  • APIView(在 rest-framework 中 CBV 所要继承的类) 的 request 对象是在 View(即: 以前CBV中所继承的类) 的 request 对象的基础上进行封装的,所以在使用在使用 rest-framework 中的 CBV 里的 request 对象是一个全新的 request 对象

  • View 的 request 对象有的功能,APIView 的 request 对象都有

2. APIView 的 request对象 所提供的常用属性:

  • request.GET -> 获取GET请求参数

# views.py

from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView


class BookView(APIView):
    def get(self, request):

        get_data = request.GET

# 等同于

        # get_data = request._request.GET

        print(get_data)  # <QueryDict: {'b': ['2'], 'a': ['1']}>

        return HttpResponse('get请求')

  • request.query_params -> 获取GET请求参数

    • request.query_params 等同于 request.GET
    • request.query_params 实际上是执行了 request._request.GET

from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView


class BookView(APIView):
    def get(self, request):

        get_data = request.query_params

        print(get_data)  # <QueryDict: {'name': ['三国演义'], 'price': ['100']}>
        print(get_data.get('name'))  # 三国演义
        print(get_data.get('price'))  # 100

        return HttpResponse('get请求')

  • request.data -> 获取除GET请求外的其他请求参数(即: POST/PUT/PATCH 等请求的参数

    • 在不使用 rest-framework 之前,request.POST 只能获取以 application/x-www-form-urlencoded 编码格式发送过来的数据,其他编码格式发送过来的数据(如: application/json)都只能通过 request.body 获取,然后自行解析,但是在 rest-framework 可以通过 request.data 获取不同编码格式发送过来的数据,并且帮我们进行解析

# views.py

from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView


class BookView(APIView):

    def post(self, request):
        data = request.data
        print(data)  # 以 application/json 编码格式提交过来的数据 -> {'name': 'Kevin', 'age': 18}
        return HttpResponse('post请求')

  • request._request -> 获取 View 的 request 对象(即: 旧的request对象)

# views.py

from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView


class BookView(APIView):
    def get(self, request):
        get_data = request._request.GET
        print(get_data)  # <QueryDict: {'b': ['2'], 'a': ['1']}>
        return HttpResponse('get请求')


    def post(self, request):
        post_data = request._request.POST
        print(post_data)  # <QueryDict: {'age': ['18'], 'name': ['Kevin']}>
        return HttpResponse('post请求')